#include "FmodFramework.h"

FmodFramework::FmodFramework()
	: m_system(0), m_version(0), m_numDrivers(0)
{
}

FmodFramework::~FmodFramework()
{
	release();
}

int FmodFramework::init()
{
	if(FM_ERROR(FMOD::System_Create(&m_system)))
		return SND_INIT_SYSTEM_ERROR;

	if(FM_ERROR(m_system->getVersion(&m_version)))
		return SND_INIT_VERSION_ERROR;

	if(m_version < FMOD_VERSION)
		return SND_INIT_VERSIONCHECK_ERROR;

	if(FM_ERROR(m_system->getNumDrivers(&m_numDrivers)))
		return SND_INIT_NUMDRIVER_ERROR;

	if(m_numDrivers == 0)
	{
		if(FM_ERROR(m_system->setOutput(FMOD_OUTPUTTYPE_NOSOUND)))
			return SND_INIT_OUTPUT_ERROR;
	}
	else
	{
		if(FM_ERROR(m_system->getDriverCaps(0,&m_caps,0,&m_mode)))
			return SND_INIT_DRIVERCAP_ERROR;

		if(FM_ERROR(m_system->setSpeakerMode(m_mode)))
			return SND_INIT_SPEAKERMODE_ERROR;

		if(m_caps & FMOD_CAPS_HARDWARE_EMULATED)
			if(FM_ERROR(m_system->setDSPBufferSize(1024,10)))
				return SND_INIT_DSPBUFFER_ERROR;

		if(FM_ERROR(m_system->getDriverInfo(0,m_name,256,0)))
			return SND_INIT_DRIVERINFO_ERROR;

		if(strstr(m_name, "SigmaTel"))
			if(FM_ERROR(m_system->setSoftwareFormat(
				48000,FMOD_SOUND_FORMAT_PCMFLOAT,0,0,
				FMOD_DSP_RESAMPLER_LINEAR)))
				return SND_INIT_SOFTWAREFORMAT_ERROR;
	}

	FMOD_RESULT result = FMOD_OK;
	if(result == m_system->init(100,FMOD_INIT_NORMAL,0))
	{
		if(result == FMOD_ERR_OUTPUT_CREATEBUFFER)
		{
			if(FM_ERROR(m_system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO)))
				return SND_INIT_SPEAKERMODE_ERROR;

			if(FM_ERROR(m_system->init(100,FMOD_INIT_NORMAL,0)))
				return SND_INIT_INIT_ERROR;
		}
		else if(FM_ERROR(result))
			return SND_INIT_INIT_ERROR;
	}
	m_system->getMasterSoundGroup(&m_MasterGroup);
	m_system->getMasterChannelGroup(&m_MasterChannel);
	return SND_SUCCESS;
}

int FmodFramework::release()
{
	for(int i = 0; i < m_audioList.size(); i++)
	{
		m_audioList.get(i)->release();
		delete m_audioList.get(i);
	}
	m_audioList.release();

	SAFE_RELEASE_LRN(m_system);
	return SND_SUCCESS;
}

int FmodFramework::update()
{
	if(FM_ERROR(m_system->update()))
		return SND_UPDT_UPDT_ERROR;
	return SND_SUCCESS;
}

int FmodFramework::loadAudio(char* a_source, void* a_audio, bool a_stream)
{
	Audio* caudio = (Audio*)a_audio;

	for(int i = 0; i < m_audioList.size(); i++)
	{
		FmodAudio* fma = m_audioList.get(i);
		if(a_source == fma->m_path)
		{
			caudio->m_id = fma->m_id;
			caudio->m_path = fma->m_path;
			return SND_SUCCESS;
		}
	}
	FmodAudio* audio = new FmodAudio();
	if(!a_stream)
	{
		if(FM_ERROR(m_system->createSound(
			a_source,FMOD_DEFAULT,0,&audio->m_audio)))
			return SND_LOAD_AUDIO_ERROR;
	}
	else
	{
		if(FM_ERROR(m_system->createStream(
			a_source,FMOD_LOOP_NORMAL|FMOD_2D|FMOD_HARDWARE,0,&audio->m_audio)))
			return SND_LOAD_AUDIO_ERROR;
	}
	audio->m_id = caudio->m_id = m_audioList.size();
	audio->m_path = caudio->m_path = a_source;
	m_channelList.insertBack(new FmodChannel());
	m_channelList.get(audio->m_id)->m_id = audio->m_id;
	m_audioList.insertBack(audio);
	return SND_SUCCESS;
}

int FmodFramework::playAudio(int a_id)
{
	FmodAudio* audio = m_audioList.get(a_id);
	FmodChannel* channel = m_channelList.get(a_id);
	if(FM_ERROR(m_system->playSound(
		FMOD_CHANNEL_FREE,audio->m_audio,false,&channel->m_channel)))
		return SND_PLAY_AUDIO_ERROR;

	return SND_SUCCESS;
}
int FmodFramework::playAudio(int a_id,int g_id)
{
	FmodAudio* audio = m_audioList.get(a_id);
	FmodChannel* channel = m_channelList.get(a_id);
	if(FM_ERROR(m_system->playSound(
		FMOD_CHANNEL_FREE,audio->m_audio,false,&channel->m_channel)))
		return SND_PLAY_AUDIO_ERROR;
	addToChannelGroup(a_id, g_id);

	return SND_SUCCESS;
}

int FmodFramework::addSoundGroup(char* name)
{
	FmodSoundGroup * group = new FmodSoundGroup();
	group->m_id = m_groups.size();
	if(FM_ERROR(m_system->createSoundGroup(name,&group->m_group)))
		return SND_CREATE_GROUP_ERROR;
	m_groups.insertBack(group);
	return SND_SUCCESS;
}

int FmodFramework::addToGroup(FmodAudio* a_audio, FmodSoundGroup* a_group)
{
	if(FM_ERROR(a_audio->m_audio->setSoundGroup(a_group->m_group)))
		return SND_ADD_TO_GROUP_ERROR;
	return SND_SUCCESS;
}

int FmodFramework::createChannelGroup(char* name, int &a_gID)
{
	a_gID = m_channelGroups.size();
	FmodChannelGroup *newChannel = new FmodChannelGroup();
	if(FM_ERROR(m_system->createChannelGroup(name, &newChannel->m_channelGroup)))
		return SND_CREATE_CHANNEL_GROUP_ERROR;

	m_channelGroups.insertBack(newChannel);
	m_MasterChannel->addGroup(newChannel->m_channelGroup);
	return SND_SUCCESS;
}
int FmodFramework::addToChannelGroup(int a_cId, int a_gId)
{
	if(FM_ERROR(m_channelList.get(a_cId)->m_channel->setChannelGroup(m_channelGroups.get(a_gId)->m_channelGroup)))
		return SND_ADD_TO_CHANNEL_GROUP_ERROR;
	return SND_SUCCESS;
}
FmodChannelGroup* FmodFramework::getChannelGroup(char* name, int len)
{
	char * temp;
	temp = new char[len];
	for (int i = 0; i < m_channelGroups.size(); i++)
	{
		m_channelGroups.get(i)->m_channelGroup->getName(temp,len);
		if(!strcmp(temp,name))
			return m_channelGroups.get(i);
	}
	return 0;
}
